#ifdef _MSWIN_
#include <windows.h>
#endif

#include "ticker.h"
#include <errno.h>
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifdef _LINUX_
#include <malloc.h>
#endif
#ifdef _MACOS_
#include <stdlib.h>
#endif

static int
down_sampler_(const Tick* tick,
              const int down_interval,
              Tick* out,
              const int len)
{
  if (down_interval == 1) {
    memcpy(out, tick, sizeof(Tick) * len);
  } else {
    Tick *d = out, *s = (Tick*)(tick);
    for (int i = 0; i < len; ++i, ++d, s += down_interval) {
      memcpy(d, s, sizeof(Tick));
    }
  }
  return (0);
}

int
down_sampler(const Tick* tick,
             const size_t tick_size,
             const int down_interval,
             const int64_t pos,
             Tick* data,
             const int target_len,
             int8_t direction)
{
  int len = 0;
  if (direction == -1) {
    int64_t tick_len = target_len * down_interval;
    // set the data len
    if (tick_len > pos) {
      len = pos / down_interval;
      tick_len = pos;
    } else {
      len = target_len;
    }

    // set the start position in tick
    int64_t spos = pos - tick_len;
    down_sampler_(tick + spos, down_interval, data, len);
  } else if (direction == 1) {
    int64_t tick_len = (target_len + 1) * down_interval;
    if (pos + tick_len >= (int64_t)(tick_size)) {
      len = (tick_size - (pos + down_interval)) / down_interval;
    } else {
      len = target_len;
    }
    int64_t spos = pos + down_interval;
    down_sampler_(tick + spos, down_interval, data, len);
  }
  return len;
}

Tick*
load_all_ticker(const char* filepath, size_t* size)
{
  int ret = 0;
  FILE* fp = fopen(filepath, "rb");
  if (fp == NULL) {
    printf("Can not open tick data %s, err %d\n", filepath, errno);
    ret = -1000;
  }

  Tick* td = NULL;
  // off64_t ofe = 0;
  off_t ofe = 0;
  size_t all = 0;
  if (!ret) {
    fseeko(fp, 0, SEEK_END);
    ofe = ftello(fp);
    if (0 != ((uint64_t)(ofe) % sizeof(Tick))) {
      ret = -1001;
    }
  }

  if (!ret) {
    all = (uint64_t)(ofe) / sizeof(Tick);

    td = malloc(sizeof(Tick) * all);
    // set the start position
    fseeko(fp, 0, SEEK_SET);

    size_t readed = fread(td, sizeof(Tick), all, fp);
    if (all != readed) {
      printf("data size is %lu, but read %ld from %s\n", all, readed, filepath);
      ret = -1002;
    } else {
      *size = all;
    }
  }

  if (fp != NULL)
    fclose(fp);

  if (ret) {
    printf("error %d\n", ret);
    if (td != NULL)
      free(td);
    td = NULL;
  }

  fflush(stdout);

  return td;
}

Tick*
load_ticker_bin(const char* filepath,
                size_t* size,
                const int64_t spos,
                const int64_t epos)
{
  int ret = 0;
  FILE* fp = fopen(filepath, "rb");
  if (fp == NULL) {
    printf("Can not open tick data %s, err %d\n", filepath, errno);
    ret = -1000;
  }

  Tick* td = NULL;
  // off64_t ofe = 0;
  off_t ofe = 0;
  int64_t all = 0;
  int64_t s = spos;
  int64_t e = epos;
  size_t len = 0;
  if (!ret) {
    fseek(fp, 0, SEEK_END);
    ofe = ftello(fp);
    if (0 != ((uint64_t)(ofe) % sizeof(Tick)))
      ret = -1001;
  }

  if (!ret) {
    all = (uint64_t)(ofe) / sizeof(Tick);

    if (s < 2099200)
      s = 2099200;
    if ((e <= s) || (e >= all))
      e = all - 1;

    len = e - s + 1;
    // alloc buffer
    td = malloc(sizeof(Tick) * len);
    // set the start position
    fseeko(fp, s * sizeof(Tick), SEEK_SET);

    size_t readed = fread(td, sizeof(Tick), len, fp);
    if (len != readed) {
      printf("data size is %lu, but read %ld from %s\n", len, readed, filepath);
      ret = -1002;
    } else {
      *size = len;
    }
  }

  if (fp != NULL)
    fclose(fp);

  if (ret) {
    printf("error %d\n", ret);
    if (td != NULL)
      free(td);
    td = NULL;
  }

  return td;
}

int64_t
find_time(const Tick* tick, const size_t tick_size, const time_t tm)
{
  for (size_t i = 0; i < tick_size; ++i) {
    if (tick[i].ftime >= tm)
      return (int64_t)(i);
  }
  return -1;
}
